<!-- 3D全景图片组件：基于PhotoSphereViewer实现的全景图查看器 -->
<template>
  <div class="photo-sphere-container">
    <!-- 全景图渲染容器 -->
    <div id="viewer" ref="viewer" class="viewer"></div>
  </div>
</template>

<script>
export default {
  name: 'PhotoSphereViewer',
  data () {
    return {
      // 全景图查看器实例
      viewer: null,
      // 标记插件实例
      markersPlugin: null,
      // 动画帧ID，用于清除动画
      animationId: null,
      // 线上资源基础路径
      baseUrl: 'https://photo-sphere-viewer-data.netlify.app/assets/',
      // 本地全景图路径（public目录下的资源需用绝对路径）
      baseUrlNew: '/2222.jpg',
    }
  },
  
  mounted () {
    // 组件挂载后初始化全景图查看器
    this.initPanoramaViewer();
  },
  
  beforeDestroy () {
    // 组件销毁前清理资源
    this.cleanupResources();
  },
  
  methods: {
    /**
     * 初始化全景图查看器的入口方法
     */
    initPanoramaViewer() {
      // 先加载必要的样式文件
      this.loadRequiredStyles();
      
      // 检查核心库是否已加载
      if (window.PhotoSphereViewer) {
        this.initializeViewer();
      } else {
        // 异步加载所需脚本，加载完成后初始化
        this.loadRequiredScripts()
          .then(() => this.initializeViewer())
          .catch(error => {
            console.error('全景图初始化错误:', error);
          });
      }
    },
    
    /**
     * 加载组件所需的样式文件
     */
    loadRequiredStyles() {
      // 加载PhotoSphereViewer核心样式
      this.loadStyle('https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/core@5/index.css');
      // 加载标记插件样式
      this.loadStyle('https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/markers-plugin@5/index.css');
    },
    
    /**
     * 动态加载单个样式文件的工具方法
     * @param {string} url - 样式文件URL
     */
    loadStyle(url) {
      // 检查样式是否已加载，避免重复加载
      if (document.querySelector(`link[href="${url}"]`)) return;
      
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = url;
      document.head.appendChild(link);
    },
    
    /**
     * 加载组件所需的脚本文件
     * @returns {Promise} - 加载完成的Promise
     */
    loadRequiredScripts() {
      return new Promise((resolve, reject) => {
        // 按依赖顺序加载脚本：Three.js → PSV核心 → 标记插件
        this.loadScript('https://cdn.jsdelivr.net/npm/three/build/three.min.js')
          .then(() => this.loadScript('https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/core/index.min.js'))
          .then(() => this.loadScript('https://cdn.jsdelivr.net/npm/@photo-sphere-viewer/markers-plugin/index.min.js'))
          .then(resolve)
          .catch(reject);
      });
    },
    
    /**
     * 动态加载单个脚本文件的工具方法
     * @param {string} url - 脚本文件URL
     * @returns {Promise} - 加载完成的Promise
     */
    loadScript(url) {
      // 检查脚本是否已加载，避免重复加载
      if (document.querySelector(`script[src="${url}"]`)) {
        return Promise.resolve();
      }
      
      return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = url;
        script.onload = resolve;
        script.onerror = () => reject(new Error(`无法加载脚本: ${url}`));
        document.head.appendChild(script);
      });
    },
    
    /**
     * 初始化全景图查看器实例
     */
    initializeViewer() {
      try {
        // 从全局对象获取所需类
        const { Viewer } = window.PhotoSphereViewer;
        const MarkersPlugin = window.PhotoSphereViewer.MarkersPlugin;
        
        // 创建查看器实例
        this.viewer = new Viewer({
          // 使用ref获取容器DOM元素，比ID选择器更可靠
          container: this.$refs.viewer,
          // 全景图路径（本地路径）
          panorama: this.baseUrlNew,
          // 全景图标题（为空时不显示）
          caption: '',
          // 默认水平视角（偏航角）
          defaultYaw: 2.5,
          // 默认垂直视角（俯仰角）
          defaultPitch: 0.1,
          // 拖动惯性效果
          moveInertia: true,
          // 加载超时设置（10秒）
          loadingTimeout: 10000,
          // 本地图片关闭跨域
          crossOrigin: null,
          // 插件配置
          plugins: [
            [MarkersPlugin, {
              markers: [] // 初始为空标记列表
            }]
          ]
        });
        
        // 获取标记插件实例
        this.markersPlugin = this.viewer.getPlugin(MarkersPlugin);
        
        // 设置事件监听器
        this.setupEventListeners();
        
        // 监听全景图加载错误
        this.viewer.addEventListener('error', (e) => {
          let errorMsg = `全景图加载失败: ${e.message}`;
          // 补充常见错误提示
          if (e.message.includes('not found')) {
            errorMsg += '（检查public目录下是否存在2222.jpg文件）';
          } else if (e.message.includes('invalid panorama')) {
            errorMsg += '（图片不是等矩形投影格式，PSV仅支持等矩形全景图）';
          }
          console.error('全景图错误详情:', e);
        });
        
        // 监听加载进度
        this.viewer.addEventListener('progress', (e) => {
          console.log(`全景图加载进度: ${Math.round(e.progress * 100)}%`);
        });
        
        // 初始化完成后设置动画
        this.setupAnimation();
        
      } catch (error) {
        console.error('初始化错误:', error);
      }
    },
    
    /**
     * 设置事件监听器
     */
    setupEventListeners() {
      // 标记点击事件处理
      this.markersPlugin.addEventListener('select-marker', ({ marker }) => {
        // 处理视频标记的播放/暂停
        if (marker.id === 'video' && marker.video) {
          marker.video.paused ? marker.video.play() : marker.video.pause();
        }
      });
    },
    
    /**
     * 设置标记动画效果
     */
    setupAnimation() {
      // 标记的多个位置点（用于动画切换）
      const positions = [
        [
          { yaw: 2.17063, pitch: 0.47556 }, { yaw: 2.47392, pitch: 0.47121 },
          { yaw: 2.47818, pitch: 0.24468 }, { yaw: 2.17698, pitch: 0.24809 },
        ],
        [
          { yaw: 2.53028, pitch: 0.45475 }, { yaw: 2.73576, pitch: 0.42324 },
          { yaw: 2.72772, pitch: 0.25040 }, { yaw: 2.52465, pitch: 0.27152 },
        ],
        [
          { yaw: 2.52182, pitch: 0.22277 }, { yaw: 2.71813, pitch: 0.20591 },
          { yaw: 2.71176, pitch: 0.04947 }, { yaw: 2.51667, pitch: 0.05490 },
        ],
        [
          { yaw: 2.24036, pitch: 0.21062 }, { yaw: 2.42582, pitch: 0.20913 },
          { yaw: 2.42649, pitch: 0.05818 }, { yaw: 2.24091, pitch: 0.05868 },
        ],
        [
          { yaw: 1.95249, pitch: 0.46809 }, { yaw: 2.11880, pitch: 0.48289 },
          { yaw: 2.12564, pitch: 0.28968 }, { yaw: 1.96142, pitch: 0.27917 },
        ],
        [
          { yaw: 2.35634, pitch: -0.08720 }, { yaw: 2.50943, pitch: -0.08660 },
          { yaw: 2.51593, pitch: -0.27962 }, { yaw: 2.35963, pitch: -0.28636 },
        ],
        [
          { yaw: 1.97055, pitch: 0.24636 }, { yaw: 2.12267, pitch: 0.25273 },
          { yaw: 2.12077, pitch: 0.14738 }, { yaw: 1.97077, pitch: 0.14508 },
        ],
        [
          { yaw: 1.73189, pitch: 0.44483 }, { yaw: 1.91183, pitch: 0.47555 },
          { yaw: 1.91775, pitch: 0.34020 }, { yaw: 1.73849, pitch: 0.31800 },
        ],
        [
          { yaw: 1.77034, pitch: 0.29604 }, { yaw: 1.88900, pitch: 0.30949 },
          { yaw: 1.89234, pitch: 0.13656 }, { yaw: 1.77210, pitch: 0.13185 },
        ],
        [
          { yaw: 1.75644, pitch: 0.10757 }, { yaw: 1.89867, pitch: 0.11271 },
          { yaw: 1.90351, pitch: 0.00480 }, { yaw: 1.76327, pitch: 0.00579 },
        ],
      ];

      // 动画状态变量
      let opacity = 1;         // 标记透明度
      let dir = -1;            // 透明度变化方向 (-1: 减小, 1: 增大)
      let lastTime = 0;        // 上一帧时间
      let waitTime = 0;        // 等待时间（停留效果）

      /**
       * 标记动画帧函数
       * @param {number} time - 当前时间戳
       */
      const animateMarker = (time) => {
        // 计算时间差
        const deltaTime = time - lastTime;
        lastTime = time;

        // 等待状态处理
        if (waitTime > 0) {
          waitTime -= deltaTime;
        } else {
          // 更新透明度
          opacity = Math.max(0, Math.min(1, opacity + dir * deltaTime / 500));
          this.markersPlugin.updateMarker({ id: 'image', opacity });

          // 透明度达到边界时的处理
          if (opacity === 0) {
            // 随机切换到新位置
            const newPosition = positions[Math.floor(Math.random() * positions.length)];
            this.markersPlugin.updateMarker({ id: 'image', position: newPosition });
            dir = 1; // 开始增大透明度
          } else if (opacity === 1) {
            dir = -1; // 开始减小透明度
            waitTime = 500; // 停留500ms
          }
        }

        // 继续下一帧动画
        this.animationId = requestAnimationFrame(animateMarker);
      };

      // 全景图准备就绪后开始动画
      this.viewer.addEventListener('ready', () => {
        lastTime = performance.now();
        this.animationId = requestAnimationFrame(animateMarker);
      });
    },
    
    /**
     * 清理资源，避免内存泄漏
     */
    cleanupResources() {
      // 清除动画
      if (this.animationId) {
        cancelAnimationFrame(this.animationId);
        this.animationId = null;
      }
      
      // 销毁全景图实例
      if (this.viewer) {
        this.viewer.destroy();
        this.viewer = null;
      }
      
      // 清空插件实例
      this.markersPlugin = null;
    }
  }
}
</script>

<style scoped lang="less">
.photo-sphere-container {
  width: 100%;
  height: 100%;
  position: relative;

  .viewer {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
}
</style>
    